#pragma once
// 对所有的文件描述符作封装
// 一个epollserver中会有很多的文件描述符，在我们看来就是有很多的链接，将所有的链接用Connection描述起来

#include "Common.hpp"
#include "InetAddr.hpp"

class Reactor;
class Connection;

// using func_t = std::function<void(shared_ptr<Connection>)>;  // 调用哪个方法，你要告诉我是哪个连接就绪了

// 要管理的链接：有listensockfd或者普通的fd
// 让对fd采取统一的处理方式
// 描述一个链接，再用unordered_map组织链接
class Connection
{
public:
    Connection()
        :_sockfd(-1)
        ,_events(0)
    {}

    void SetPeerInfo(const InetAddr& peer_addr)
    {
        _peer_addr = peer_addr;
    }

    void SetEvents(uint32_t events)
    {
        _events = events;
    }

    void SetSockfd(int sockfd)
    {
        _sockfd = sockfd;
    }

    uint32_t GetEvents()
    {
        return _events;
    }

    void SetOwner(Reactor* owner)
    {
        _owner = owner;
    }

    Reactor* GetOwner()
    {
        return _owner;
    }

    // void CallRecv(shared_ptr<Connection> conn)
    // {
    //     if(_recver != nullptr)
    //         _recver(conn);
    // }

    // void CallSend(shared_ptr<Connection> conn)
    // {
    //     if(_sender != nullptr)
    //         _sender(conn);
    // }

    int Sockfd()
    {
        return _sockfd;
    }

    void Append(const std::string& in)
    {
        _inbuffer += in;
    }

    void AppendToOut(const std::string& out)
    {
        _outbuffer += out;
    }

    // 用来移除已经发送的缓冲区的内容，方便下次发送或者判定退出
    void DiscardOutBuffer(int n)
    {
        _outbuffer.erase(0,n);
    }

    string& GetInbuffer()  // 注意这里是引用，因为会拿走缓冲区的数据，要实时更新
    {
        return _inbuffer;
    }

    string& GetOutBuffer()  // 注意这里是引用，因为会拿走缓冲区的数据，要实时更新
    {
        return _outbuffer;
    }

    void Close()
    {
        if(_sockfd >= 0)
            close(_sockfd);
    }

    ~Connection(){}
protected:  // 想让他们继承下去

    // 对于单个的链接必须要有一下字段
    int _sockfd;  // 文件描述符
    std::string _inbuffer;  // 接受缓冲区
    std::string _outbuffer;  // 发送缓冲区
    InetAddr _peer_addr;  // 远端的客户端

    /* 
     添加一个指针，这个指针回指着该Connection所属的epollserver，到时候比如listensockfd获取了一个新的sockfd，就可以通过这个指针得到对应的epollserver，
     然后可以直接执行比如InsertConnection的方法，就可以直接管理链接（unordered_map）
    */
    Reactor* _owner;

    // 我这个fd关心的事件
    uint32_t _events;

public:  // 方法要公有继承
    // 回调方法
    // func_t _recver;  // 读
    // func_t _sender;  // 写
    // func_t _excepter;  // 异常
    virtual void Sender() = 0;
    virtual void Recver() = 0;
    virtual void Excepter() = 0;
};


// class Factory
// {
// public:
//     // 建立一个Connection对象，因为epollserver只认Connection，在epoll模型中管理的都是一个个的Connection，所以每一个文件描述符都应该包装成一个Connection对象
//     static std::shared_ptr<Connection> BuildConnection(int sockfd, uint32_t events, func_t recver, func_t sender, func_t excepter)
//     {
//         std::shared_ptr<Connection> ret = std::make_shared<Connection>(sockfd);
//         ret->InitCB(recver,sender,excepter);
//         ret->SetEvents(events);
//         return ret;
//     }
// };